{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "hub_with_keras.ipynb",
      "version": "0.3.2",
      "provenance": [],
      "private_outputs": true,
      "collapsed_sections": [
        "W_tvPdyfA-BL"
      ],
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "accelerator": "GPU"
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "W_tvPdyfA-BL"
      },
      "source": [
        "##### Copyright 2018 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "form",
        "colab_type": "code",
        "id": "0O_LFhwSBCjm",
        "colab": {}
      },
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "PWUmcKKjtwXL"
      },
      "source": [
        "# Hub with Keras"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bAF5fnbcq5_Q",
        "colab_type": "text"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs/blob/master/site/ja/r1/tutorials/images/hub_with_keras.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Run in Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs/blob/master/site/ja/r1/tutorials/images/hub_with_keras.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />View source on GitHub</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MzXvBPp0IkoD",
        "colab_type": "text"
      },
      "source": [
        "Note: これらのドキュメントは私たちTensorFlowコミュニティが翻訳したものです。コミュニティによる 翻訳は**ベストエフォート**であるため、この翻訳が正確であることや[英語の公式ドキュメント](https://www.tensorflow.org/?hl=en)の 最新の状態を反映したものであることを保証することはできません。 この翻訳の品質を向上させるためのご意見をお持ちの方は、GitHubリポジトリ[tensorflow/docs](https://github.com/tensorflow/docs)にプルリクエストをお送りください。 コミュニティによる翻訳やレビューに参加していただける方は、 [docs-ja@tensorflow.org メーリングリスト](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs-ja)にご連絡ください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "crU-iluJIEzw"
      },
      "source": [
        "[TensorFlow Hub](http://tensorflow.org/hub) は事前学習済みモデルのコンポーネントを共有する一つの方法です。事前学習済みモデルの検索可能なリストは  [TensorFlow Module Hub](https://tfhub.dev/) をご覧ください。\n",
        "\n",
        "このチュートリアルでは以下の事を説明します。\n",
        "\n",
        "1. tf.keras での TensorFlow Hub の使い方\n",
        "1. TensorFlow Hub を使って画像を分類する方法\n",
        "1. シンプルな転移学習の方法"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "CKFUvuEho9Th"
      },
      "source": [
        "## セットアップ"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "7RVsYZLEpEWs"
      },
      "source": [
        "### インポート"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "nSiOCtv_Rwi_",
        "colab": {}
      },
      "source": [
        "!pip install -U tensorflow_hub\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "OGNpmn43C0O6",
        "colab": {}
      },
      "source": [
        "from __future__ import absolute_import, division, print_function, unicode_literals\n",
        "\n",
        "import matplotlib.pylab as plt\n",
        "\n",
        "import tensorflow as tf\n",
        "tf.enable_eager_execution()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "-V4l8oN8Lw2q",
        "colab": {}
      },
      "source": [
        "import tensorflow_hub as hub\n",
        "\n",
        "from tensorflow.keras import layers"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "s4YuF5HvpM1W"
      },
      "source": [
        "## ImageNet 分類器"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "xEY_Ow5loN6q"
      },
      "source": [
        "### 分類器をダウンロードする\n",
        "\n",
        "mobilenet をロードするには hub.module を、それを keras レイヤーとしてまとめるには tf.keras.layers.Lambda を使ってください。\n",
        "\n",
        "tfhub.dev にある [TensorFlow 1.x の画像分類器 URL](https://tfhub.dev/s?module-type=image-classification) であればすべてここで動作します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "both",
        "colab_type": "code",
        "id": "feiXojVXAbI9",
        "colab": {}
      },
      "source": [
        "classifier_url =\"https://tfhub.dev/google/tf2-preview/mobilenet_v2/classification/2\" #@param {type:\"string\"}"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "y_6bGjoPtzau",
        "colab": {}
      },
      "source": [
        "IMAGE_SHAPE = (224, 224)\n",
        "\n",
        "classifier = tf.keras.Sequential([\n",
        "    hub.KerasLayer(classifier_url, input_shape=IMAGE_SHAPE+(3,))\n",
        "])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "pwZXaoV0uXp2"
      },
      "source": [
        "### 単一の画像で実行する"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "TQItP1i55-di"
      },
      "source": [
        "モデルを試すために単一の画像をダウンロードしてください。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "w5wDjXNjuXGD",
        "colab": {}
      },
      "source": [
        "import numpy as np\n",
        "import PIL.Image as Image\n",
        "\n",
        "grace_hopper = tf.keras.utils.get_file('image.jpg','https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg')\n",
        "grace_hopper = Image.open(grace_hopper).resize(IMAGE_SHAPE)\n",
        "grace_hopper"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "BEmmBnGbLxPp",
        "colab": {}
      },
      "source": [
        "grace_hopper = np.array(grace_hopper)/255.0\n",
        "grace_hopper.shape"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "0Ic8OEEo2b73"
      },
      "source": [
        "バッチ次元を一つ追加し、画像をモデルに渡してください。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "EMquyn29v8q3",
        "colab": {}
      },
      "source": [
        "result = classifier.predict(grace_hopper[np.newaxis, ...])\n",
        "result.shape"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "NKzjqENF6jDF"
      },
      "source": [
        "結果は 1001 の要素をもつロジットベクトルで、画像がそれぞれのクラスに属する確率を表します。\n",
        "\n",
        "そのため、もっとも確率の高いクラスの ID は argmax でみつけることができます。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "rgXb44vt6goJ",
        "colab": {}
      },
      "source": [
        "predicted_class = np.argmax(result[0], axis=-1)\n",
        "predicted_class"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "YrxLMajMoxkf"
      },
      "source": [
        "### 予測結果をデコードする\n",
        "\n",
        "予測されたクラスの ID を ImageNet のラベルと突き合わせて、予測結果をデコードします。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "ij6SrDxcxzry",
        "colab": {}
      },
      "source": [
        "labels_path = tf.keras.utils.get_file('ImageNetLabels.txt','https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt')\n",
        "imagenet_labels = np.array(open(labels_path).read().splitlines())"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "uzziRK3Z2VQo",
        "colab": {}
      },
      "source": [
        "plt.imshow(grace_hopper)\n",
        "plt.axis('off')\n",
        "predicted_class_name = imagenet_labels[predicted_class]\n",
        "_ = plt.title(\"Prediction: \" + predicted_class_name.title())"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "amfzqn1Oo7Om"
      },
      "source": [
        "## シンプルな転移学習"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "K-nIpVJ94xrw"
      },
      "source": [
        "TF Hub を利用すると、私たちが用意したデータセット内のクラスを認識するために、モデルの最上位層を再学習する事が容易になります。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Z93vvAdGxDMD"
      },
      "source": [
        "### データセット\n",
        "\n",
        "この例では、TensorFlow の花データセットを使用します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "DrIUV3V0xDL_",
        "colab": {}
      },
      "source": [
        "data_root = tf.keras.utils.get_file(\n",
        "  'flower_photos','https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz',\n",
        "   untar=True)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "jFHdp18ccah7"
      },
      "source": [
        "このデータをモデルに読み込むもっとも簡単な方法は、 tf.keras.preprocessing.image.ImageDataGenerator を使用することです。\n",
        "\n",
        "TensorFlow Hub のすべての画像モジュールは、  [0, 1] の範囲の float 入力を想定しています。これを実現するには ImageDataGenerator の rescale パラメータを使用してください。\n",
        "\n",
        "画像のサイズについては後で処理されます。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "2PwQ_wYDcii9",
        "colab": {}
      },
      "source": [
        "image_generator = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1/255)\n",
        "image_data = image_generator.flow_from_directory(str(data_root), target_size=IMAGE_SHAPE)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "0p7iDOhIcqY2"
      },
      "source": [
        "結果のオブジェクトは、image_batch と label_batch のペアを返すイテレータです。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "W4lDPkn2cpWZ",
        "colab": {}
      },
      "source": [
        "for image_batch, label_batch in image_data:\n",
        "  print(\"Image batch shape: \", image_batch.shape)\n",
        "  print(\"Label batch shape: \", label_batch.shape)\n",
        "  break"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "0gTN7M_GxDLx"
      },
      "source": [
        "### 画像のバッチに対して分類器を実行する"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "O3fvrZR8xDLv"
      },
      "source": [
        "それでは、画像のバッチで分類器を実行します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "nbyg6tcyxDLh",
        "colab": {}
      },
      "source": [
        "result_batch = classifier.predict(image_batch)\n",
        "result_batch.shape"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "Kv7ZwuR4xDLc",
        "colab": {}
      },
      "source": [
        "predicted_class_names = imagenet_labels[np.argmax(result_batch, axis=-1)]\n",
        "predicted_class_names"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "QmvSWg9nxDLa"
      },
      "source": [
        "これらの予測結果と実際の画像がどの程度一致しているか確認してください。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "IXTB22SpxDLP",
        "colab": {}
      },
      "source": [
        "plt.figure(figsize=(10,9))\n",
        "plt.subplots_adjust(hspace=0.5)\n",
        "for n in range(30):\n",
        "  plt.subplot(6,5,n+1)\n",
        "  plt.imshow(image_batch[n])\n",
        "  plt.title(predicted_class_names[n])\n",
        "  plt.axis('off')\n",
        "_ = plt.suptitle(\"ImageNet predictions\")"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "FUa3YkvhxDLM"
      },
      "source": [
        "画像の属性については、 LICENSE.txt ファイルを参照してください。\n",
        "\n",
        "結果は完全には程遠いですが、これらがこのモデルのために学習されたクラスでない事を考えると悪くはないです（ 「デイジー」を除く）。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "JzV457OXreQP"
      },
      "source": [
        "### ヘッドレスモデルをダウンロードする\n",
        "\n",
        "TensorFlow Hub はさらに、最上位の分類層がないモデルを配布することもしています。これらは転移学習を簡単に行うために使用することができます。\n",
        "\n",
        "tfhub.dev からの [TensorFlow 1.x の画像特徴ベクトルの URL](https://tfhub.dev/s?module-type=image-feature-vector) はすべてここで動作します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "both",
        "colab_type": "code",
        "id": "4bw8Jf94DSnP",
        "colab": {}
      },
      "source": [
        "feature_extractor_url = \"https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/2\" #@param {type:\"string\"}"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "sgwmHugQF-PD"
      },
      "source": [
        "モジュールを作成し、入力として期待される画像サイズを確認します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "5wB030nezBwI",
        "colab": {}
      },
      "source": [
        "feature_extractor_layer = hub.KerasLayer(feature_extractor_url,\n",
        "                                         input_shape=(224,224,3))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "GUY-5Eyzuzlu"
      },
      "source": [
        "特徴抽出器は、各画像に対して 1280 要素のベクトルを返します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "Of7i-35F09ls",
        "colab": {}
      },
      "source": [
        "feature_batch = feature_extractor_layer(image_batch)\n",
        "print(feature_batch.shape)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "CtFmF7A5E4tk"
      },
      "source": [
        "学習が新しい分類層のみを修正するように、特徴抽出層の変数を freeze（固定）します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "Jg5ar6rcE4H-",
        "colab": {}
      },
      "source": [
        "feature_extractor_layer.trainable = False"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "RPVeouTksO9q"
      },
      "source": [
        "### 分類ヘッドを追加する\n",
        "\n",
        "hub レイヤーを tf.keras.Sequential モデルでラップし、新しい分類層を一つ追加します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "mGcY27fY1q3Q",
        "colab": {}
      },
      "source": [
        "model = tf.keras.Sequential([\n",
        "  feature_extractor_layer,\n",
        "  layers.Dense(image_data.num_classes, activation='softmax')\n",
        "])\n",
        "\n",
        "model.summary()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "G9VkAz00HOJx",
        "colab": {}
      },
      "source": [
        "predictions = model(image_batch)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "sB7sVGJ23vrY",
        "colab": {}
      },
      "source": [
        "predictions.shape"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "OHbXQqIquFxQ"
      },
      "source": [
        "### モデルを学習する\n",
        "\n",
        "学習プロセスを構成するために、 compile を使用してください。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "3n0Wb9ylKd8R",
        "colab": {}
      },
      "source": [
        "model.compile(\n",
        "  optimizer=tf.keras.optimizers.Adam(),\n",
        "  loss='categorical_crossentropy',\n",
        "  metrics=['acc'])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "58-BLV7dupJA"
      },
      "source": [
        "今度は .fit メソッドを使ってモデルを学習します。\n",
        "\n",
        "この例を短くするために、2エポックだけ学習を実行します。学習の進行状況を可視化するには、エポック平均ではなく、カスタムコールバックを使用して各バッチの損失と精度を個別に記録します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "jZ54Gubac4Lu",
        "colab": {}
      },
      "source": [
        "class CollectBatchStats(tf.keras.callbacks.Callback):\n",
        "  def __init__(self):\n",
        "    self.batch_losses = []\n",
        "    self.batch_acc = []\n",
        "\n",
        "  def on_train_batch_end(self, batch, logs=None):\n",
        "    self.batch_losses.append(logs['loss'])\n",
        "    self.batch_acc.append(logs['acc'])\n",
        "    self.model.reset_metrics()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "EyMDJxt2HdHr",
        "colab": {}
      },
      "source": [
        "steps_per_epoch = np.ceil(image_data.samples/image_data.batch_size)\n",
        "\n",
        "batch_stats_callback = CollectBatchStats()\n",
        "\n",
        "history = model.fit(image_data, epochs=2,\n",
        "                    steps_per_epoch=steps_per_epoch,\n",
        "                    callbacks = [batch_stats_callback])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Kd0N272B9Q0b"
      },
      "source": [
        "これで、ほんの数回の学習の繰り返しでも、モデルがタスクを進めていることがわかったと思います。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "A5RfS1QIIP-P",
        "colab": {}
      },
      "source": [
        "plt.figure()\n",
        "plt.ylabel(\"Loss\")\n",
        "plt.xlabel(\"Training Steps\")\n",
        "plt.ylim([0,2])\n",
        "plt.plot(batch_stats_callback.batch_losses)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "3uvX11avTiDg",
        "colab": {}
      },
      "source": [
        "plt.figure()\n",
        "plt.ylabel(\"Accuracy\")\n",
        "plt.xlabel(\"Training Steps\")\n",
        "plt.ylim([0,1])\n",
        "plt.plot(batch_stats_callback.batch_acc)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "kb__ZN8uFn-D"
      },
      "source": [
        "### 予測結果を確認する\n",
        "\n",
        "前からプロットをやり直すには、まずクラス名の順序付きリストを取得します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "JGbEf5l1I4jz",
        "colab": {}
      },
      "source": [
        "class_names = sorted(image_data.class_indices.items(), key=lambda pair:pair[1])\n",
        "class_names = np.array([key.title() for key, value in class_names])\n",
        "class_names"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "4Olg6MsNGJTL"
      },
      "source": [
        "モデルを介してイメージバッチを実行し、インデックスをクラス名に変換します。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "fCLVCpEjJ_VP",
        "colab": {}
      },
      "source": [
        "predicted_batch = model.predict(image_batch)\n",
        "predicted_id = np.argmax(predicted_batch, axis=-1)\n",
        "predicted_label_batch = class_names[predicted_id]"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "CkGbZxl9GZs-"
      },
      "source": [
        "結果をプロットします。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "rpFQR1MPMtT1",
        "colab": {}
      },
      "source": [
        "label_id = np.argmax(label_batch, axis=-1)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "wC_AYRJU9NQe",
        "colab": {}
      },
      "source": [
        "plt.figure(figsize=(10,9))\n",
        "plt.subplots_adjust(hspace=0.5)\n",
        "for n in range(30):\n",
        "  plt.subplot(6,5,n+1)\n",
        "  plt.imshow(image_batch[n])\n",
        "  color = \"green\" if predicted_id[n] == label_id[n] else \"red\"\n",
        "  plt.title(predicted_label_batch[n].title(), color=color)\n",
        "  plt.axis('off')\n",
        "_ = plt.suptitle(\"Model predictions (green: correct, red: incorrect)\")"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "uRcJnAABr22x"
      },
      "source": [
        "## モデルをエクスポートする\n",
        "\n",
        "モデルの学習が完了したので、saved model としてエクスポートします。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "PLcqg-RmsLno",
        "colab": {}
      },
      "source": [
        "import time\n",
        "t = time.time()\n",
        "\n",
        "export_path = \"/tmp/saved_models/{}\".format(int(t))\n",
        "tf.keras.experimental.export_saved_model(model, export_path)\n",
        "\n",
        "export_path"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "AhQ9liIUsPsi"
      },
      "source": [
        "それではモデルをリロードできることを確認してください。リロードしたモデルでもおなじ結果が得られます。"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "7nI5fvkAQvbS",
        "colab": {}
      },
      "source": [
        "reloaded = tf.keras.experimental.load_from_saved_model(export_path, custom_objects={'KerasLayer':hub.KerasLayer})"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "jor83-LqI8xW",
        "colab": {}
      },
      "source": [
        "result_batch = model.predict(image_batch)\n",
        "reloaded_result_batch = reloaded.predict(image_batch)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "dnZO14taYPH6",
        "colab": {}
      },
      "source": [
        "abs(reloaded_result_batch - result_batch).max()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "TYZd4MNiV3Rc"
      },
      "source": [
        "この saved model は後で推論のためにロードするか、もしくは [TFLite](https://www.tensorflow.org/lite/convert/) か [TFjs](https://github.com/tensorflow/tfjs-converter).に変換することができます。"
      ]
    }
  ]
}